import java.util.Random;
import java.util.Scanner;

class mmain {
    static boolean spielGesamtTrue;

    // türme
    static int frei = 0;
    static int normalTower = 1;
    static int aoeTower = 2;
    static int slowTower = 3;
    static int blitzTower = 4;
    static int[] preiseTower = {2, 4, 2, 5};
    static int[][] preiseTowerLevel = {
        {1, 2, 2, 3},
        {4, 6, 8, 10},
        {2, 2, 3, 4},
        {3, 6, 9, 10}
    };

    // spielfeld
    static int[][] spielfeld = new int[5][5];

    // level
    static int[][] level = new int[5][5];
    static int[][] gegnerpos;

    // counter
    static int coins = 10;
    static int runden;
    static int levelSpiel;

    // display
    static String[][] display = {
        {"", "1", "2", "3", "4", "5", " Ziel"},
        {"1", "", "", "", "", ""},
        {"2", "", "", "", "", ""},
        {"3", "", "", "", "", ""},
        {"4", "", "", "", "", ""},
        {"5", "", "", "", "", ""},
        {"-", "-", "-", "-", "-", "-", "-"},
        {"", "", "", "", "", "", ""}
    };

    static char[] towerChar = {'T', 'A', 'S', 'B'};

    // eigenschaften der Tower ([towertyp][level])
    static int[][] schaden = {
        {1, 2, 3, 4, 5},
        {1, 1, 2, 2, 3},
        {0, 0, 0, 0, 0},
        {3, 3, 4, 5, 5}
    };

    // cooldown 1 ist min weil -1
    static int[][] cooldownMax = {
        {3, 2, 2, 1, 1},
        {4, 4, 3, 3, 2},
        {2, 2, 1, 1, 1},
        {5, 4, 4, 3, 3}
    };

    static int[][] radius = {
        {0, 0, 0, 0, 0},
        {1, 2, 2, 2, 3},
        {0, 0, 0, 0, 0},
        {0, 0, 0, 0, 0}
    };

    static int[][] cooldown = new int[5][5];

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        regeln();
        spielGesamtTrue = true;

        while (spielGesamtTrue) {
            boolean abfrage = true;

            while (abfrage) {
                System.out.println("""
Tippe *shop* um neue Tower zu setzen.
Tippe *runde* um eine Runde zu starten.
Tippe *counter* um den Spielstand abzurufen.
""");
                String spielerEingabe = scanner.nextLine();

                switch (spielerEingabe) {
                    case "shop":
                        shop();
                        System.out.println("");
                        displayAusgabeNurTower();
                        break;

                    case "runde":
                        cooldown = new int[5][5];
                        abfrage = false;
                        break;

                    case "counter":
                        counterAusgeben();
                        break;

                    default:
                        System.out.println("ungültige Eingabe");
                        break;
                }
            }

            levelSpiel = runden;
            boolean spielTrue = true;
            boolean checkSieg = true;
            spielfeldVorbereiten();

            while (spielTrue) {
                checkSieg = true;
                spielDurchlauf();
                boolean niederlage = false;

                for (int j = 0; j < gegnerpos.length; j++) {
                    if (gegnerpos[j][1] > 0 && gegnerpos[j][0] >= 6) {
                        niederlage = true;
                        spielTrue = false;
                        break;
                    } else if (gegnerpos[j][1] > 0) {
                        checkSieg = false;
                    }
                }

                if (!spielTrue) {
                    displayAusagbe();
                }

                if (niederlage) {
                    System.out.println("Niederlage");
                    System.out.println("Das wurde erreicht:");
                    counterAusgeben();
                    spielGesamtTrue = false;
                } else if (checkSieg) {
                    spielTrue = false;
                    coins += gegnerpos.length;
                    abfrage = true;
                    displayAusagbe();
                    System.out.println("Sieg");
                    counterAusgeben();
                    runden++;
                }
            }
        }
    }

    public static void displayAusgabeNurTower() {
        display = new String[][]{
            {"", "1", "2", "3", "4", "5", " Ziel"},
            {"1", "", "", "", "", "", ""},
            {"2", "", "", "", "", "", ""},
            {"3", "", "", "", "", "", ""},
            {"4", "", "", "", "", "", ""},
            {"5", "", "", "", "", "", ""},
            {"-", "-", "-", "-", "-", "-", "-"},
            {"", "", "", "", "", "", ""}
        };

        for (int i = 1; i < 6; i++) {
            for (int j = 1; j < 6; j++) {
                if (spielfeld[i - 1][j - 1] > 0) {
                    display[i][j] += towerChar[spielfeld[i - 1][j - 1] - 1];
                    display[i][j] += level[i - 1][j - 1];
                }
            }
        }

        for (int i = 0; i < display.length; i++) {
            for (int j = 0; j < display[i].length; j++) {
                System.out.printf("%4s", display[i][j]);
            }
            System.out.println();
        }
        System.out.println();
    }

    public static void shop() {
        Scanner scanner = new Scanner(System.in);
        System.out.println("""
Tippe *kaufen* um einen neuen Tower zu kaufen.
Tippe *leveln* um einen bestehenden Tower zu leveln.
""");
        String spielerEingabe = scanner.nextLine();

        switch (spielerEingabe) {
            case "kaufen":
                System.out.println("Preise:");
                System.out.println("normaler Tower (1):" + preiseTower[0]);
                System.out.println("AOE Tower (2): " + preiseTower[1]);
                System.out.println("Slow Tower (3) Noch nicht fertig: " + preiseTower[2]);
                System.out.println("Blitz Tower (4): " + preiseTower[3]);
                System.out.println("");
                System.out.println("Welcher Tower soll gekauft werden? (Zahl)");
                int weTowerKauf = scanner.nextInt();

                if (coins >= preiseTower[weTowerKauf - 1]) {
                    System.out.println("Eingabe der x-Kordinate");
                    int xKord = scanner.nextInt() - 1;
                    System.out.println("Eingabe der y-Kordinate");
                    int yKord = scanner.nextInt() - 1;

                    if (spielfeld[yKord][xKord] == frei) {
                        spielfeld[yKord][xKord] = weTowerKauf;
                        level[yKord][xKord] = 1;
                        coins -= preiseTower[weTowerKauf - 1];
                        System.out.println("Kauf erfolgriech");
                    } else {
                        System.out.println("Feld schon belegt");
                    }
                } else {
                    System.out.println("Nicht genügend Coins");
                }
                break;

            case "leveln":
                System.out.println("Preise:");
                for (int i = 0; i < preiseTowerLevel.length; i++) {
                    for (int j = 0; j < preiseTowerLevel[i].length; j++) {
                        System.out.print(preiseTowerLevel[i][j] + " ");
                    }
                    System.out.println();
                }
                System.out.println();
                System.out.println("Eingabe der x-Kordinate des Towers, der gelevelt werden soll:");
                int xKord = scanner.nextInt() - 1;
                System.out.println("Eingabe der y-Kordinate des Towers:");
                int yKord = scanner.nextInt() - 1;

                if (spielfeld[yKord][xKord] == frei) {
                    System.out.println("Hier steht kein Tower");
                    break;
                }

                if (level[yKord][xKord] < level.length) {
                    if (coins >= preiseTowerLevel[spielfeld[yKord][xKord]][level[yKord][xKord] - 1]) {
                        coins -= preiseTowerLevel[spielfeld[yKord][xKord]][level[yKord][xKord] - 1];
                        level[yKord][xKord]++;
                        System.out.println("Kauf erfolgriech");
                    } else {
                        System.out.println("Nicht genügend Coins");
                    }
                } else {
                    System.out.println("Tower hat schon das maximale Level");
                }
                break;
        }
    }

    public static void regeln() {
        runden = 1;
        System.out.println("""
Regeln:
In diesem TowerDefense-Spiel gibt es folgende Tower:
- Normaler Turm
--> greift nur einen Gegner gleichzeitig an
- AOE-Turm
--> greift Gegner in einem bestimmten Radius an
- Blitz-Turm
--> greift eine Kette (mehrere hintereinander stehende Gegner) an
- Slow-Turm
--> senkt die Geschwindigkeit von Gegnern
--> macht keinen Schaden
Die Tower können in einem Spielfeld von 5 Feldern Länge und 5 Feldern Breite platziert werden.
Ein Feld entspricht einem Platz für einen Tower.
Tower können nicht zerstört werden. Der Platz ist begrenzt.
Mit Coins (der Währung) können neue Tower und bessere Level gekauft werden.
Ein Tower hat einen Cooldown, der mit einem besseren Level sinkt.
Der Schaden eines Towers steigt mit dem Level.
Die Gegner bewegen sich unterhalb der platzierten Tower auf einer Linie.
Gegner werden an zufälligen Stellen vor oder im Spielfeld generiert und bewegen sich vorwärts.
Erreicht ein Gegner das Ziel, während er noch lebt, hat man verloren.
Besiegt man alle Gegner, gewinnt man die Runde und erhält Coins pro eliminiertem Gegner.
Verliert man eine Runde, ist der Spielstand verloren.
""");
    }

    public static void counterAusgeben() {
        System.out.println("Level: " + levelSpiel);
        System.out.println("Runden: " + runden);
        System.out.println("Coins: " + coins);
    }

    public static void spielfeldVorbereiten() {
        Random random = new Random();
        int rZahl;
        int min;
        int max;
        int lebenGeg;
        int anzahlGegner;

        switch (levelSpiel) {
            case 1:
                min = -1;
                max = 0;
                lebenGeg = 1;
                anzahlGegner = 1;
                break;

            case 2:
                min = -5;
                max = 0;
                lebenGeg = 1;
                anzahlGegner = 2;
                break;

            case 3:
                min = -7;
                max = 1;
                lebenGeg = 2;
                anzahlGegner = 3;
                break;

            default:
                anzahlGegner = 2 + levelSpiel * 2;
                lebenGeg = 2 + levelSpiel * levelSpiel / 2;
                min = -anzahlGegner;
                max = 2;
                
                //blockirungen 
    
                break;
        }

        gegnerpos = new int[anzahlGegner][2];

        for (int i = 0; i < gegnerpos.length; i++) {
            boolean weiter;
            do {
                rZahl = random.nextInt(max - min + 1) + min;
                weiter = false;
                for (int j = 0; j < i; j++) {
                    if (gegnerpos[j][0] == rZahl) {
                        weiter = true;
                    }
                }
            } while (weiter);

            gegnerpos[i][0] = rZahl;
            gegnerpos[i][1] = lebenGeg;
        }
    }

    public static void displayAusagbe() {
        display = new String[][]{
            {"", "1", "2", "3", "4", "5", " Ziel"},
            {"1", "", "", "", "", "", ""},
            {"2", "", "", "", "", "", ""},
            {"3", "", "", "", "", "", ""},
            {"4", "", "", "", "", "", ""},
            {"5", "", "", "", "", "", ""},
            {"-", "-", "-", "-", "-", "-", "-"},
            {"", "", "", "", "", "", ""}
        };

        for (int i = 1; i < 6; i++) {
            for (int j = 1; j < 6; j++) {
                if (spielfeld[i - 1][j - 1] > 0) {
                    display[i][j] += towerChar[spielfeld[i - 1][j - 1] - 1];
                    display[i][j] += level[i - 1][j - 1];
                }
            }
        }

        for (int i = 0; i < gegnerpos.length; i++) {
            if (gegnerpos[i][0] >= 0 && gegnerpos[i][0] < display[7].length && gegnerpos[i][1] > 0) {
                display[7][gegnerpos[i][0]] = "G" + gegnerpos[i][1];
            }
        }

        for (int i = 0; i < display.length; i++) {
            for (int j = 0; j < display[i].length; j++) {
                System.out.printf("%4s", display[i][j]);
            }
            System.out.println();
        }
        System.out.println();
    }

    static void spielDurchlauf() {
        for (int i = 0; i < spielfeld.length; i++) {
            for (int j = 0; j < spielfeld[0].length; j++) {
                if (cooldown[i][j] > 0) {
                    cooldown[i][j]--;
                }
            }
        }

        displayAusagbe();

        int y;
        int x;
        int wTower;
        int wLevel;
        int wSchaden;
        int wCooldownMax;
        int wRadius;

        for (int i = 0; i < spielfeld.length; i++) {
            for (int j = 0; j < gegnerpos.length; j++) {
                y = i;
                x = gegnerpos[j][0];

                if (gegnerpos[j][0] >= 0 && gegnerpos[j][0] <= 4) {
                    if (cooldown[y][x] == 0 && spielfeld[y][x] > frei) {
                        wTower = spielfeld[y][x];
                        wLevel = level[y][x];
                        wSchaden = schaden[wTower - 1][wLevel - 1];
                        wCooldownMax = cooldownMax[wTower - 1][wLevel - 1];
                        wRadius = radius[wTower - 1][wLevel - 1];

                        for (int k = -wRadius; k <= wRadius; k++) {
                            for (int l = 0; l < gegnerpos.length; l++) {
                                if (gegnerpos[l][0] == x + k) {
                                    gegnerpos[l][1] -= wSchaden;
                                }
                            }
                        }

                        if (wTower == blitzTower && x - 1 >= 0) {
                            for (int k = x - 1; k >= 0; k--) {
                                boolean keinerHinter = false;
                                for (int l = 0; l < gegnerpos.length; l++) {
                                    keinerHinter = true;
                                    if (gegnerpos[l][0] == k) {
                                        keinerHinter = false;
                                        gegnerpos[l][1] -= wSchaden;
                                    }
                                }
                                if (keinerHinter) {
                                    break;
                                }
                            }
                        }

                        cooldown[y][x] = wCooldownMax;
                    }
                }
            }
        }

        for (int i = 0; i < gegnerpos.length; i++) {
            if (gegnerpos[i][1] > 0) {
                gegnerpos[i][0]++;
            }
        }
    }
}